/*******************************************************************************
 * Copyright (c) 2010 liw.
 * All rights reserved. 
 * 
 * This file is part of VanBus.
 * 
 *     VanBus is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     VanBus is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with VanBus.  If not, see <http://www.gnu.org/licenses/>.
 * Contributors:
 *     liw - initial API and implementation
 ******************************************************************************/
package org.niclab.vanbus.activity.controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.niclab.vanbus.R;
import org.niclab.vanbus.activity.StopListOfRouteAct;
import org.niclab.vanbus.activity.comp.StartStopReminderDialog;
import org.niclab.vanbus.application.VanBusApplication;
import org.niclab.vanbus.database.ApplicationDataBase;
import org.niclab.vanbus.database.BusRouteDAO;
import org.niclab.vanbus.database.BusStopDAO;
import org.niclab.vanbus.database.ReminderDAO;
import org.niclab.vanbus.model.BusRoute;
import org.niclab.vanbus.model.BusStop;
import org.niclab.vanbus.model.EndStopReminder;
import org.niclab.vanbus.model.StartStopReminder;
import org.niclab.vanbus.query.BusStopCoordinatesQuery;
import org.niclab.vanbus.query.RouteStopsWithTimesQuery;
import org.niclab.vanbus.query.RoutesAtStopQuery;
import org.niclab.vanbus.query.SimpleQueryWorker;
import org.niclab.vanbus.query.WalkingDirectionQuery;
import org.niclab.vanbus.query.command.DismissDialogCmd;
import org.niclab.vanbus.query.command.ShowDialogCmd;
import org.niclab.vanbus.query.handler.IQueryHandler;
import org.niclab.vanbus.query.mem.SimpleMemQueryHandler;
import org.niclab.vanbus.query.ws.GoogleDirectionWSQueryResResolver;
import org.niclab.vanbus.query.ws.RouteStopsWithTimesWSQueryResResolver;
import org.niclab.vanbus.query.ws.SimpleWSQueryHandler;
import org.niclab.vanbus.query.ws.StopCoordsWSQueryResResolver;
import org.niclab.vanbus.query.ws.StopTimesWSQueryResResolver;
import org.niclab.vanbus.query.ws.StopCoordsWSQueryResResolver.QueryResult;
import org.niclab.vanbus.utils.CacheUtils;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.AsyncQueryHandler;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.util.Log;

public class BusStopController {
	
	private static final String LOG_TAG = "BusStopController";


	private BusStop stop;
	
	public BusStopController(){
	}
	
	public BusStopController(BusStop stop){
	
		this.stop=stop;

		
		
	}

	public void setBusStop(BusStop stop){
		this.stop=stop;
		
	}

	
	
	public SimpleQueryWorker queryStopGeoLoc(final BusStop stop){
		
		SimpleQueryWorker worker = new SimpleQueryWorker();
		final BusStopCoordinatesQuery coordQuery = new BusStopCoordinatesQuery();
		
		SimpleMemQueryHandler memQueryHandler = new SimpleMemQueryHandler(coordQuery){

			@Override
			public void query() {
				if(stop.getLatitude() != 0.0d && stop.getLongitude() != 0.0d){
					coordQuery.setQueryFinished(true);
				}
				
			}
			
		};
		
		worker.addSyncQueryHandler(memQueryHandler);
		
		coordQuery.addQueryInputParam(BusStopCoordinatesQuery.InputParams.BUS_STOP_ID, stop.getStopId());
		
		//Stop Coordinates web response Handler
		StopCoordsWSQueryResResolver coordResHandler = new StopCoordsWSQueryResResolver();
		SimpleWSQueryHandler coordQHandler =new SimpleWSQueryHandler(coordQuery, coordResHandler){
			
			@Override
			public void onPostQuery(){
				StopCoordsWSQueryResResolver.QueryResult qResult = (QueryResult) coordQuery.getQueryResult();
				stop.setLatitude(qResult.getLat());
				stop.setLongitude(qResult.getLng());
			}
		};
		
		worker.addAsyncQueryHandler(coordQHandler);
		
		return worker;
		
	}

	public SimpleQueryWorker queryWalkingDirectionToStop(final Location curLoc){
		
		
		SimpleQueryWorker worker = queryStopGeoLoc(stop);
		
		//retrieve walking distance and estimated time
						
		final WalkingDirectionQuery walkingQuery = new WalkingDirectionQuery();
		if(curLoc != null){
			walkingQuery.addQueryInputParam(WalkingDirectionQuery.InputParams.START_LOC_LAT, curLoc.getLatitude());
			walkingQuery.addQueryInputParam(WalkingDirectionQuery.InputParams.START_LOC_LNG, curLoc.getLongitude());
		}
		//walking query response handler
		GoogleDirectionWSQueryResResolver walkingResHandler= new GoogleDirectionWSQueryResResolver();
		//walking query Handler
		SimpleWSQueryHandler walkingQHandler = new SimpleWSQueryHandler(walkingQuery, walkingResHandler){
			
			@Override
			public void onPreQuery(){
				//get the best estimation of current location
				if(curLoc == null){
					Location loc=VanBusApplication.getInstance().getMyLocationManager().getCurrentBestLocation(3000);
					walkingQuery.addQueryInputParam(WalkingDirectionQuery.InputParams.START_LOC_LAT, loc.getLatitude());
					walkingQuery.addQueryInputParam(WalkingDirectionQuery.InputParams.START_LOC_LNG, loc.getLongitude());
				}
				walkingQuery.addQueryInputParam(WalkingDirectionQuery.InputParams.END_LOC_LAT, stop.getLatitude());
				walkingQuery.addQueryInputParam(WalkingDirectionQuery.InputParams.END_LOC_LNG, stop.getLongitude());

				
			}

		};
		
		//connect coordinates query and walking query together
		/*IQueryHandler lastQueryHandler = worker.getAsyncQueryHandler();
		while(lastQueryHandler.getNextQueryHandler()!=null)
			lastQueryHandler = lastQueryHandler.getNextQueryHandler();
		
		lastQueryHandler.setNextQueryHandler(walkingQHandler);*/
		worker.addAsyncQueryHandler(walkingQHandler);
			
		return worker;
		
		
	}
	

	
	public SimpleQueryWorker loadRoutesByStop(final BusStop stop){
		
		//query
		final RoutesAtStopQuery query = new RoutesAtStopQuery();

		query.addQueryInputParam(RoutesAtStopQuery.InputParams.BUS_STOP_ID, stop.getStopId());
		
		//worker
		SimpleQueryWorker worker = new SimpleQueryWorker();
	
		//web service
		StopTimesWSQueryResResolver resHandler = new StopTimesWSQueryResResolver();
		IQueryHandler qHandler = new SimpleWSQueryHandler(query, resHandler){
			@Override
			public void onPostQuery(){
				StopTimesWSQueryResResolver.QueryResult result = (org.niclab.vanbus.query.ws.StopTimesWSQueryResResolver.QueryResult) query.getQueryResult();
				stop.setBusTimes(result.getRoutesWithTimes());
				
				
				//hit the database to check favorite routes
				//check the database if there are any favorite bus stops
				BusRouteDAO routeDao = new BusRouteDAO(ApplicationDataBase.getSQLiteOpenHelper());
				routeDao.checkFavoriteRoutes(new ArrayList<BusRoute>(result.getRoutesWithTimes().keySet()));
			}
		};
		
		worker.addAsyncQueryHandler(qHandler);
		
		
		return worker;
	}

	
	public SimpleQueryWorker updateStopSchedule(final BusRoute route){
		
		//query
		final RoutesAtStopQuery query = new RoutesAtStopQuery();

		query.addQueryInputParam(RoutesAtStopQuery.InputParams.BUS_STOP_ID, stop.getStopId());
		//worker
		SimpleQueryWorker worker = new SimpleQueryWorker();
	
		//web service
		StopTimesWSQueryResResolver resHandler = new StopTimesWSQueryResResolver();
		IQueryHandler qHandler = new SimpleWSQueryHandler(query, resHandler){
			
			@Override
			public void onPostQuery(){
				StopTimesWSQueryResResolver.QueryResult result = (org.niclab.vanbus.query.ws.StopTimesWSQueryResResolver.QueryResult) query.getQueryResult();
				List<String> times = result.getTimes(route);
				if(stop.getBusTimes().containsKey(route)){
					Log.d(LOG_TAG,"times updated for route"+route.getRouteId());
					stop.getTimes(route).clear();
					stop.getTimes(route).addAll(times);
				}else{
					stop.putTimes(route, times);
				}
				
				//stop.setRefreshed(true);
			}
			
		};
		
		worker.addAsyncQueryHandler(qHandler);
		
		
		return worker;
		
	}
	
	/**
	 * fetch the BusStop object from cache, if it exists
	 * @param stopId stopId as the key to retrieve the object
	 * @return null if not exists
	 */
	public BusStop createBusStopFromCache(String stopId){
		return CacheUtils.getCachedBusStop(stopId);
	}
	

	/**create a BusStop object from cache or database. If this object doesn't exist
	 * in cache, it will be created from database.
	 * This method should be avoided to use unless it's necessary, because it's relatively slow reading from database. 
	 * @param cursor the cursor to a bus stop record in Stop table
	 * @return a BusStop object
	 * 
	 */
	public BusStop createBusStopFromDB(Cursor cursor){
		
		String stopId=cursor.getString(cursor.getColumnIndex("STOP_ID"));
		BusStop stop = CacheUtils.getCachedBusStop(stopId);
		if(stop ==null){
			BusStopDAO dao= new BusStopDAO(ApplicationDataBase.getSQLiteOpenHelper());
			stop = dao.getBusStop(cursor);
		}
		return stop;
			
		
			
	}
	
	
		

	/**create a BusStop object from cache or database. If this object doesn't exist
	 * in cache, it will be created from database.
	 * This method should be avoided to use unless it's necessary, because it's relatively slow reading from database. 
	 * @param stopId stop Id
	 * @return  null if this stop doesn't exist in cache or database.
	 * 
	 */
	public BusStop createBusStopFromCacheAndDB(String stopId){
		BusStop stop = CacheUtils.getCachedBusStop(stopId);
		
		if(stop == null){
			BusStopDAO dao= new BusStopDAO(ApplicationDataBase.getSQLiteOpenHelper());
			stop = dao.getBusStop(stopId);
			
		}
				
		return stop;
	}


	/**
	 * 
	 * @param dbId the id of this stop record in STOP table 
	 * @return a BusStop object
	 */
	public BusStop createBusStopFromDB(int dbId){
		BusStopDAO dao= new BusStopDAO(ApplicationDataBase.getSQLiteOpenHelper());
		return dao.getBusStop(dbId);
	}
	

	/**
	 * stop object will be put to cache first.
	 * Then it will be saved to database.
	 * @param stop BusStop object to be saved
	 * @param update whether to update the database if stop is already in the database
	 */
	public void saveOrUpdateBusStop(BusStop stop,boolean update){
		
		CacheUtils.saveBusStopToCache(stop);
		
		BusStopDAO dao= new BusStopDAO(ApplicationDataBase.getSQLiteOpenHelper());
		dao.saveOrUpdateBusStop(stop,update);
		
			
	}
	
	public void addFavoriteStop(Context context){
		
		BusStopDAO stopDao = new BusStopDAO(ApplicationDataBase.getSQLiteOpenHelper());
		stopDao.setFavoriteStop(stop);
		stop.setFavorite(true);
		context.sendBroadcast(new Intent(context.getString(R.string.favorites_tab_stop_update)));
	}

	
	
	
	public void cancelFavoriteStop(Context context){
		
		BusStopDAO stopDao = new BusStopDAO(ApplicationDataBase.getSQLiteOpenHelper());
		stopDao.unsetFavoriteStop(stop);
		stop.setFavorite(false);
		context.sendBroadcast(new Intent(context.getString(R.string.favorites_tab_stop_update)));
		
	}

	
	
}
